home *** CD-ROM | disk | FTP | other *** search
/ The 640 MEG Shareware Studio 5 / The 640 Meg Shareware Studio CD-ROM Volume V (Data Express)(1994).ISO / amiga / tndbrgcn.lha / TandbergConf.c < prev   
C/C++ Source or Header  |  1994-02-23  |  14KB  |  656 lines

  1. /*
  2.  *****    TandbergConf
  3.  *
  4.  *    A utility to configure Tandberg TDC3600 SCSI Tape drives.
  5.  *
  6.  *        - Turn on/off Auto retension
  7.  *        - Settings can be permanant or will reset after a re-boot/power on
  8.  *
  9.  *    Note: 
  10.  *        This code was hacked from an excellent program called SCSIutil,
  11.  *        written by Gary Duncan (gduncan@philips.oz.au), modified by
  12.  *        Heiko Rath (hr@brewhr.swb.de) 
  13.  *
  14.  *        Information on how to program the TDC3600 was provided by Goncal
  15.  *        Badenes (badenes@imec.be)
  16.  *    
  17.  *    Program returns:
  18.  *    1 - init didn't work (maybe allocmem failed, etc.)
  19.  *    2 - wrong parameter count
  20.  *    3 - wrong parameter
  21.  *
  22.  */
  23.  
  24. #define VERSION "1.0"
  25.  
  26. /*
  27.  **** Includes
  28.  */
  29. #include <stdlib.h>
  30. #include <stdio.h>
  31. #include <string.h>
  32. #include <ctype.h>
  33. #include <exec/types.h>
  34. #include <exec/io.h>
  35. #include <exec/execbase.h>
  36. #include <exec/nodes.h>
  37. #include <exec/memory.h>
  38. #include <devices/trackdisk.h>
  39. #include <devices/scsidisk.h>
  40. #include <dos/rdargs.h>
  41. #include <libraries/dos.h>
  42. #ifdef __SASC
  43. #include <proto/all.h>
  44. #endif
  45. #include "scsi_priv.h"
  46.  
  47. /*
  48.  **** Global variables
  49.  */
  50. UBYTE *scsi_data = NULL;
  51.  
  52. UBYTE *dev = "";
  53.  
  54. int scsi_id = -1;        /* ID of the SCSI device to send commands to */
  55. UBYTE *pname;
  56. UBYTE buffer[LINE_BUF];
  57. int secno = -1;
  58.  
  59. MSGPORT *mp_ptr;
  60. IOSTDREQ *io_ptr;
  61. SCSICMD scsi_cmd;
  62. UBYTE *scsi_sense;
  63. UBYTE scsi_status;
  64.  
  65.  
  66. /*
  67.  **** Function descr.
  68.  */
  69. int breakcheck (void);
  70. int DoScsiCmd (UBYTE * data, int datasize, UBYTE * cmd, int cmdsize, UBYTE flags, BOOLEAN);
  71. UBYTE *err_str (int err);
  72. void exit (int status);
  73. UBYTE *GetDevName (char *grep);
  74. BOOLEAN init (void);
  75. void inquiry (void);
  76. void mode_sense (BOOLEAN parsed, UBYTE control, UBYTE page);
  77. void rawhexasciioutput (UBYTE *p, UWORD numbytes, UBYTE leadspace);
  78. UBYTE *sense_errs (int req, int err);
  79. void usage (void);
  80. void write_mode(BOOLEAN, UBYTE *, int);
  81. void parse_mode(void);
  82.  
  83. #ifdef __SASC
  84. void __regargs __chkabort (void);
  85. #endif    /* __SASC */
  86. #define RAW ra_array[2]
  87. #define RETENSION ra_array[3]
  88. #define AUTOLOAD ra_array[4]
  89. #define SAVE ra_array[5]
  90. #define QUIET ra_array[6]
  91.  
  92. /*********************************************************************
  93.  *
  94.  *    main
  95.  *
  96.  *
  97.  */
  98.  
  99. int
  100. main (int argc, char **argv)
  101. {
  102.   long ra_array[7] = {0,0,0,0,0,0,0};
  103.   struct RDArgs *ra;
  104.   static UBYTE cmd_data[24];
  105.   int returnvalue = 0;
  106.  
  107.   if (argc == 1)
  108.     {
  109.       usage ();
  110.       exit (1);
  111.     }
  112.     
  113.     ra = ReadArgs("UNIT/N/R,DEVICE/K,RAW/S,RETENSION/S,AUTOLOAD/S,SAVE/S,QUIET/S", ra_array, NULL);
  114.     if (!ra) {
  115.         usage();
  116.         return 3;
  117.     }
  118.     
  119.   /*
  120.    *      see if a SCSI.device specified
  121.    */
  122.   if (ra_array[1])
  123.       dev = (char *)ra_array[1];
  124.   else if ((dev = GetDevName (SCSI_STRING)) == NULL)
  125.     {
  126.       fprintf (stderr, "Error : no *scsi*.device in device list\n");
  127.       returnvalue = 1;
  128.       goto error;
  129.     }
  130.   pname = argv[0];
  131.  
  132.    scsi_id = *(long *)ra_array[0];
  133.   /*
  134.    *    now set up structures etc for SCSI xfer
  135.    */
  136.   if (init () == FALSE)
  137.     {
  138.       returnvalue = 1;
  139.       goto error;
  140.     }
  141.     
  142.      mode_sense(FALSE,0,0);
  143.    inquiry();
  144.    if (strncmp(&scsi_data[8], "TANDBERG", 8)) {
  145.            fprintf(stderr, "Device not a Tandberg drive!\n");
  146.            returnvalue = 2;
  147.            goto error;
  148.        }
  149.  
  150. /*
  151.  * read the mode sense data. We do this twice due to the fact that for some
  152.  * reason, the first one fails.
  153.  */
  154.  
  155.      mode_sense(FALSE,0,0);
  156.      mode_sense(TRUE,0,0);
  157.      
  158.      if (!QUIET) {
  159.          printf("Current Configuration:\n");
  160.          if (RAW)
  161.             rawhexasciioutput(scsi_data, scsi_data[0]+1, 0);
  162.         else
  163.             parse_mode();
  164.     }
  165.     if (RETENSION | AUTOLOAD) {
  166.         memcpy(cmd_data, scsi_data,24);
  167.         cmd_data[0] = 0x00;
  168.         cmd_data[1] = 0x00;
  169.         
  170.         if (RETENSION)
  171.             cmd_data[22] = 0x01;
  172.         if (AUTOLOAD)
  173.             cmd_data[22] = 0x00;
  174.             
  175.         if(SAVE)
  176.             write_mode(TRUE, cmd_data, 24);
  177.         else
  178.             write_mode(FALSE, cmd_data, 24);
  179.             
  180.          if (!QUIET) {
  181.              mode_sense(TRUE,0,0);
  182.              printf("New Configuration:\n");
  183.              if (RAW)
  184.                 rawhexasciioutput(scsi_data, scsi_data[0]+1, 0);
  185.             else
  186.                 parse_mode();
  187.         }
  188.     }
  189.  
  190. error:
  191.  
  192.     FreeArgs(ra);
  193.  
  194.       if (io_ptr)
  195.     {
  196.       CloseDevice ((struct IORequest *) io_ptr);
  197.       DeleteStdIO (io_ptr);
  198.     }
  199.  
  200.       if (mp_ptr)
  201.     DeletePort (mp_ptr);
  202.  
  203.       if (scsi_sense)
  204.     FreeMem (scsi_sense, SENSE_LEN);
  205.  
  206.   if (scsi_data)
  207.     FreeMem (scsi_data, MAX_DATA_LEN);
  208.  
  209.   exit (returnvalue);
  210. }
  211.  
  212. /*********************************************************************
  213.  * DWL
  214.  *    function to write mode select info to a Tandberg drive
  215.  */
  216.  
  217. void
  218. write_mode(BOOLEAN permanant, UBYTE *cmd_data, int cmd_data_len)
  219. {
  220.   static SCSICMD6 command =
  221.   {
  222.     0x15,/* 0x15 MODE SELECT scsi command */
  223.     0,            /* LUN | rsrvd. | DBD | rsrvd. */
  224.     0,            /* PC | Page Code */
  225.     0,            /* rsrvd. */
  226.     0x00,        /* allocation length */
  227.     0x00        /* control */
  228.   };
  229. /*  static __chip UBYTE cmd_data[24] = {
  230.     0,0,0x10,8,0x10,0,0,0,0,0,2,0,0,2,2,0x78,0,0,8,0,0,0,0,0x64 
  231.   }; */
  232.  
  233.  
  234.   int err;
  235.  
  236.     if (permanant)
  237.         command.control = 0x40;
  238.     else
  239.         command.control = 0x00;
  240.         
  241.     command.b4 = cmd_data_len;
  242.         
  243.   if ((err = DoScsiCmd ((UBYTE *) cmd_data, cmd_data_len,
  244.                         (UBYTE *) &command, sizeof (command),
  245.                         (SCSIF_WRITE | SCSIF_AUTOSENSE), TRUE)) != 0)
  246.     {
  247.       fprintf (stderr, "Error : err=%ld , %s \n", err, sense_errs (0, err));
  248.     }
  249. }
  250.  
  251. /*********************************************************************
  252.  *
  253.  *    Initialization function
  254.  *
  255.  */
  256. BOOLEAN
  257. init (void)
  258. {
  259.  
  260.   if ((scsi_data = (UBYTE *) AllocMem (MAX_DATA_LEN, MEMF_CHIP | MEMF_CLEAR)) == NULL)
  261.     {
  262.       fprintf (stderr, "AllocMem(0) Fail\n");
  263.       return FALSE;
  264.     }
  265.  
  266.       if ((scsi_sense = (UBYTE *) AllocMem (SENSE_LEN, MEMF_CHIP || MEMF_CLEAR)) == NULL)
  267.     {
  268.       fprintf (stderr, "AllocMem (scsi_sense) Fail\n");
  269.       return FALSE;
  270.     }
  271.       if ((mp_ptr = (MSGPORT *) CreatePort (NULL, 0)) == NULL)
  272.     {
  273.       fprintf (stderr, "CreatePort (mp_ptr) Fail\n");
  274.       return FALSE;
  275.     }
  276.       if ((io_ptr = (IOSTDREQ *) CreateStdIO (mp_ptr)) == NULL)
  277.     {
  278.       fprintf (stderr, "CreateStdIO (io_ptr) Fail\n");
  279.       return FALSE;
  280.     }
  281.       if (OpenDevice (dev, scsi_id, (struct IORequest *) io_ptr, 0) != 0)
  282.     {
  283.       fprintf (stderr,
  284.            "Error %d while opening SCSI dev \"%s\", unit (%d)\n",
  285.            io_ptr->io_Error, dev, scsi_id);
  286.       return FALSE;
  287.     }
  288.  
  289.   return TRUE;
  290. }
  291.  
  292. /*********************************************************************
  293.  *
  294.  *    function to read parameter pages from a device
  295.  */
  296.  
  297. void
  298. mode_sense (BOOLEAN error_chk, UBYTE control, UBYTE page)
  299. {
  300.   static SCSICMD6 command =
  301.   {
  302.     SCSI_CMD_MSE,    /* 0x1a MODE SENSE scsi command */
  303.     PAD,        /* LUN | rsrvd. | DBD | rsrvd. */
  304.     0,            /* PC | Page Code */
  305.     PAD,        /* rsrvd. */
  306.     0,            /* allocation length */
  307.     PAD            /* control */
  308.   };
  309.  
  310.   int err;
  311.  
  312.   command.b2 = (control<<6) | page;
  313.   command.b4 = MAX_DATA_LEN;
  314.  
  315.   err = DoScsiCmd ((UBYTE *) scsi_data, MAX_DATA_LEN,
  316.                         (UBYTE *) &command, sizeof (command),
  317.                         (SCSIF_READ | SCSIF_AUTOSENSE), error_chk);
  318.   if (err != 0) {
  319.       if (error_chk)
  320.       fprintf (stderr, "Error : err=%ld , %s \n", err, sense_errs (0, err));
  321.   }
  322. }
  323.  
  324. /*********************************************************************
  325.  *
  326.  * subroutine used to printout raw hex data bytes with the
  327.  * corresponding ASCII values and an index
  328.  *
  329.  */
  330. void
  331. rawhexasciioutput (UBYTE *p, UWORD numbytes, UBYTE leadspace)
  332. {
  333.   UWORD i, j;
  334.   UBYTE *boff, *aoff;
  335.   int xxxlen = strlen (" xx");            /* byte */
  336.  
  337.   buffer[5+leadspace] = '=';
  338.  
  339.   for (i = 0; i < numbytes; i += BYTES_PER_LINE)
  340.     {
  341.       memset (buffer, ' ', sizeof (buffer));    /* put spaces in buffer */
  342.       boff = &buffer[7+leadspace];
  343.       aoff = boff + (xxxlen * BYTES_PER_LINE) + 1;
  344.  
  345.       sprintf (buffer+leadspace, "%04X = ", i);        /* add offset */
  346.  
  347.       for (j = 0; (j < BYTES_PER_LINE && (i+j) < numbytes); j++, boff += xxxlen, p++, aoff++)
  348.         {
  349.           sprintf (boff, " %02X", *p);
  350.           *aoff = (isascii (*p) && isprint (*p)) ? *p : '.';
  351.         }
  352.  
  353.       buffer[strlen (buffer)] = ' ';
  354.       *++aoff = '\n';
  355.       *++aoff = '\0';
  356.       printf ("%s", buffer);
  357.     }
  358. }
  359.  
  360. /*********************************************************************
  361.  *
  362.  *    function to make an inquiry
  363.  *
  364.  */
  365.  
  366. void
  367. inquiry ()
  368. {
  369.   static SCSICMD6 command =
  370.   {
  371.     SCSI_CMD_INQ,        /* 0x12 INQUIRY */
  372.     PAD,            /* Bits 7-5 Logical Unit Number | Bits 4-1 Reserved | Bit 0 EVPD */
  373.     PAD,            /* Page Code */
  374.     PAD,            /* Reserved */
  375.     0,                /* Allocation length */
  376.     PAD                /* Control */
  377.   };
  378.  
  379.   int err;
  380.  
  381.   command.b4 = MAX_DATA_LEN;    /* Allocation length = max. data length */
  382.  
  383.   if ((err = DoScsiCmd ((UBYTE *) scsi_data, MAX_DATA_LEN,
  384.             (UBYTE *) & command, sizeof (command),
  385.             (SCSIF_READ | SCSIF_AUTOSENSE), TRUE)) != 0)
  386.       fprintf (stderr, "Inquiry Error : err=%ld , %s\n", err, sense_errs (0, err));
  387. }
  388.  
  389. /*********************************************************************
  390.  *
  391.  * searches DeviceList for a device name with a given string in it.
  392.  * - if found returns with a pointer to it, else NULL
  393.  */
  394.  
  395. extern struct ExecBase *SysBase;
  396.  
  397. UBYTE *
  398. GetDevName (char *grep)
  399. {
  400.   LIST *lh = (LIST *) SysBase->DeviceList.lh_Head;
  401.   NODE *ln;
  402.  
  403.   for (ln = lh->lh_Head; ln->ln_Succ; ln = ln->ln_Succ)
  404.     {
  405.       UBYTE *p = ln->ln_Name;
  406.  
  407.       while (*p != '.')
  408.     {
  409.       if (strncmp (p, grep, 4) == 0)
  410.         {
  411.           return (ln->ln_Name);
  412.         }
  413.       ++p;
  414.     }
  415.     }
  416.  
  417.   return (NULL);        /* not found */
  418. }
  419.  
  420. /*********************************************************************
  421.  *
  422.  *    Break (^C) function
  423.  *
  424.  */
  425.  
  426. int
  427. breakcheck (void)
  428. {
  429.   int zz = SetSignal (0L, SIGBREAKF_CTRL_C) & SIGBREAKF_CTRL_C;
  430.   if (zz)
  431.     {
  432.       printf ("\n***BREAK: ^C\n");
  433.     }
  434.   return (zz);
  435. }
  436.  
  437. #ifdef __SASC
  438. /*********************************************************************
  439.  *
  440.  *  tell SAS to turn of CTRL-C checking
  441.  */
  442. void __regargs
  443. __chkabort (void)
  444. {
  445. }
  446.  
  447. #endif
  448.  
  449. /*********************************************************************
  450.  *
  451.  *    function to use a scsi command
  452.  *
  453.  */
  454. int
  455. DoScsiCmd (UBYTE * data, int datasize, UBYTE * cmd, int cmdsize, UBYTE flags, BOOLEAN error_report)
  456. {
  457.   int i;
  458.  
  459.   io_ptr->io_Length = sizeof (SCSICMD);
  460.   io_ptr->io_Data = (APTR) & scsi_cmd;
  461.   io_ptr->io_Command = HD_SCSICMD;
  462.  
  463.   scsi_cmd.scsi_Data = (APTR) data;
  464.   scsi_cmd.scsi_Length = datasize;
  465.   scsi_cmd.scsi_SenseActual = 0;
  466.   scsi_cmd.scsi_SenseData = scsi_sense;
  467.   scsi_cmd.scsi_SenseLength = SENSE_LEN;
  468.   scsi_cmd.scsi_Command = cmd;
  469.   scsi_cmd.scsi_CmdLength = cmdsize;
  470.   scsi_cmd.scsi_Flags = flags;
  471.  
  472.   (void) DoIO ((struct IORequest *) io_ptr);
  473.  
  474.   if (scsi_cmd.scsi_SenseActual && error_report)
  475.     {
  476.       fprintf (stderr, "SENSE_DATA:");
  477.       for (i = 0; i < scsi_cmd.scsi_SenseActual; i++)
  478.     {
  479.       fprintf (stderr, " %02x", scsi_cmd.scsi_SenseData[i]);
  480.     }
  481.       fprintf (stderr, "\n");
  482.     }
  483.   return (io_ptr->io_Error);
  484. }
  485.  
  486. /*********************************************************************
  487.  *
  488.  *    function to return an error string
  489.  *
  490.  *
  491.  */
  492.  
  493. UBYTE *
  494. err_str (int err)
  495. {
  496.  
  497.   static UBYTE *errors[] =
  498.   {
  499.     " cannot issue SCSI command to self ",
  500.     " DMA error ",
  501.     " illegal or unexpected SCSI phase ",
  502.     " SCSI parity error ",
  503.     " Select timed out ",
  504.     " status and/or sense error "
  505.   };
  506.  
  507.   err -= 40;
  508.  
  509.   if ((err < 0) || (err > 5))
  510.     return ("Error out-of-range");
  511.   else
  512.     return (errors[err]);
  513. }
  514.  
  515. /*********************************************************************
  516.  *
  517.  *    usage function
  518.  *
  519.  *
  520.  */
  521.  
  522. void
  523. usage (void)
  524. {
  525.   static char *zz[] =
  526.   {
  527.     "Usage: TandbergConf [UNIT] unit [DEVICE devname] [RAW] [RETENSION | AUTOLOAD] [SAVE] [QUIET]\n",
  528.     " where:\n",
  529.     "     unit =       (Required) SCSI unit number of Tandberg tape drive\n",
  530.     "     devname =    SCSI device name (Default scsi.device)\n",
  531.     "     RAW =        Show configuration in hex mode(Default, text mode)\n",
  532.     "     RETENSION =  Retension tape when inserted or on reset\n",
  533.     "     AUTOLOAD =   Position tape at load point when inserted or on reset\n",
  534.     "     SAVE =       Make changes permanant (Default, temporary)\n",
  535.     "     QUIET =      Do not print configuration(s)\n",
  536.     ""                /* TERM */
  537.   };
  538.  
  539.   int j = 0;
  540.  
  541.   fprintf (stderr, "TandbergConf V%s [%s : %s] - written by Dave Lowrey\n",
  542.        VERSION, __DATE__, __TIME__, pname);
  543.  
  544.   while (*zz[j++])
  545.     fprintf (stderr, "%s", zz[j - 1]);
  546. }
  547.  
  548. /*********************************************************************
  549.  *
  550.  *    sense_errs function ; prints sense errors
  551.  *
  552.  *
  553.  */
  554.  
  555. UBYTE *
  556. sense_errs (int req, int err)
  557. {
  558.   typedef struct
  559.   {
  560.     BYTE code;
  561.     BYTE sense;
  562.     UBYTE *ptr;
  563.   } S_ERRS;
  564.  
  565. /*
  566.  *    only the likely, interesting ones filled in, e.g media errors
  567.  */
  568.   static S_ERRS x[] =
  569.   {
  570.     0x00, 0x00, "No error",
  571.     0x01, 0x04, "?",
  572.     0x02, 0x04, "?",
  573.     0x03, 0x04, "?",
  574.     0x04, 0x02, "?",
  575.     0x06, 0x04, "?",
  576.     0x09, 0x04, "?",
  577.     0x10, 0x03, "?",
  578.     0x10, 0x04, "?",
  579.     0x11, 0x03, "?",
  580.     0x12, 0x03, "?",
  581.     0x13, 0x03, "?",
  582.     0x14, 0x03, "?",
  583.     0x15, 0x04, "Seek error ",
  584.     0x17, 0x01, "?",
  585.     0x18, 0x01, "?",
  586.     0x19, 0x03, "?",
  587.     0x1A, 0x05, "?",
  588.     0x20, 0x05, "Invalid command op code",
  589.     0x21, 0x05, "Illegal sector address",
  590.     0x24, 0x05, "?",
  591.     0x25, 0x05, "Invalid LUN",
  592.     0x26, 0x05, "Invalid field in parameter list",
  593.     0x29, 0x06, "?",
  594.     0x2A, 0x06, "?",
  595.     0x31, 0x03, "?",
  596.     0x32, 0x01, "?",
  597.     0x32, 0x03, "?",
  598.     0x40, 0x04, "?",
  599.     0x41, 0x04, "?",
  600.     0x42, 0x04, "Power-on diagnostic failure",
  601.     0x43, 0x04, "?",
  602.     0x45, 0x04, "Select / reselect failure ",
  603.     0x47, 0x04, "SCSI Interface Parity Error",
  604.     0x48, 0x0B, "?",
  605.     0x49, 0x0B, "Illegal message drive can't support",
  606.     -1, -1, "ILLEGAL sense!!"
  607.   };
  608.  
  609.   int j = 0;
  610.   UBYTE *p;
  611.   char sense;
  612.   char code;
  613.  
  614.   /*
  615.    *    verify that sense data looks valid
  616.    */
  617.   if (((scsi_cmd.scsi_Status & 2) == 0) ||
  618.       (scsi_cmd.scsi_SenseActual < OFFS_KEY))
  619.     {
  620.       return ("");
  621.     }
  622.   sense = scsi_cmd.scsi_SenseData[OFFS_KEY] & 0xF;
  623.   code = scsi_cmd.scsi_SenseData[OFFS_CODE];
  624.  
  625.   do
  626.     {
  627.       p = x[j].ptr;
  628.       if ((x[j].code == code) && (x[j].sense == sense))
  629.     break;
  630.   } while (x[j++].code != -1);
  631.  
  632.   return (p);
  633. }
  634.  
  635. void parse_mode()
  636. {
  637.  
  638. /*    printf("Density: ");
  639.     if(scsi_data[4] == 0x00)
  640.         printf("Default\n");
  641.     else if (scsi_data[4] == 0x0f)
  642.         printf("QIC-120\n");
  643.     else if (scsi_data[4] == 0x10)
  644.         printf("QIC-150\n");
  645.     else
  646.         printf("Unknown\n");
  647. */        
  648.     printf("Load Function: ");
  649.     if (scsi_data[22] == 0x00)
  650.         printf("AUTOLOAD\n");
  651.     else if (scsi_data[22] == 0x01)
  652.         printf("RETENSION\n");
  653.     else
  654.         printf("Unknown\n");
  655. }
  656.